package com.fengye.redisson.star.service.impl;

import com.fengye.redisson.star.dto.PraiseRankDTO;
import com.fengye.redisson.star.mapper.PraiseMapper;
import com.fengye.redisson.star.service.RedisPraiseService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author sky
 * @date 2021年06月16日 2:11 下午
 */

@Service
@Slf4j
public class RedisPraiseServiceImpl implements RedisPraiseService {

    private static final String blogMapKey = "redis-blog-map-key";

    @Autowired
    private RedissonClient client;

    @Resource
    PraiseMapper praiseMapper;


    @Override
    public void cachePraiseBlog(Integer blogId, Integer uId, Integer status) throws Exception {
        final String lockName = "blogRedissonPraiseLock" + blogId + uId + status;
        RLock lock = client.getLock(lockName);

        // 可重入锁
        boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);

        try {
            if (res) { // 获得锁
                final String key = blogId + ":" + uId;
                RMap<String, Integer> praiseMap = client.getMap(blogMapKey);
                if (status == 1) {
                    praiseMap.putIfAbsent(key, uId);
                } else if (0 == status) {
                    praiseMap.remove(key);
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            lock.forceUnlock();
        }
    }

    /**
     * 根据 blogId 获取博客的总点赞数
     * @param blogId 博客 id
     * @return java.lang.Long
     */
    @Override
    public Long getCacheTotalBlog(Integer blogId) throws Exception {
        long result = 0L;
        if (blogId != null) {
            RMap<String, Integer> praiseMap = client.getMap(blogMapKey);
            Map<String, Integer> dataMap = praiseMap.readAllMap();
            log.info("获取所有缓存的博客 map={}", dataMap);
            if (dataMap != null) {
                Set<String> keySet = dataMap.keySet();

                Integer bId;
                for (String key : keySet) {
                    if (StringUtils.hasText(key)) {
                        String[] arr = key.split(":");
                        if (arr.length > 0) {
                            bId = Integer.valueOf(arr[0]);
                            // 判断当前取出的键对应的博客 id 是否跟当前待比较的博客 id 相等
                            if (bId.equals(blogId)) {
                                result += 1;
                            }
                        }
                    }
                }
            }
        }

        return result;
    }

    @Override
    public void rankBlogPraise() throws Exception {
        //定义用于缓存排行榜的Key
        final String key = "praiseRankListKey";
        //根据数据库查询语句得到已经排好序的博客实体对象列表
        List<PraiseRankDTO> list = praiseMapper.getPraiseRank();
        //判断列表中是否有数据
        if (list != null && list.size() > 0) {
            //获取Redisson的列表组件RList实例
            RList<PraiseRankDTO> rList = client.getList(key);
            //先清空缓存中的列表数据
            rList.clear();
            //将得到的最新的排行榜更新至缓存中
            rList.addAll(list);
        }
    }

    @Override
    public List<PraiseRankDTO> getBlogPraiseRank() throws Exception {
        //定义用于缓存排行榜的Key
        final String key = "praiseRankListKey";
        //获取Redisson的列表组件RList实例
        RList<PraiseRankDTO> rList = client.getList(key);
        //获取缓存中最新的排行榜
        return rList.readAll();
    }
}
